#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time     : 2018/9/7 下午3:35
# @File     : mongo_api.py
# @Function : MongoDB 数据库管理类

import logging
from pymongo import MongoClient
from motor.motor_asyncio import AsyncIOMotorClient

import traceback

class MongoManager(object):

    """MongoDB 数据库管理类"""
    # 配置文件解析对象
    _PARSER = None
    # 客户端
    _CLIENT = {}
    # def __init__(self, host, port, db, password,decode_responses=True):
    #     self.pool = redis.ConnectionPool(host=host, port=port, db=db, password=password, decode_responses=decode_responses)
    #     self._conn = redis.Redis(connection_pool=self.pool)

    def __init__(self,mongo_config):
        host = mongo_config.host
        port = mongo_config.port
        user = mongo_config.user
        pwd = mongo_config.pwd
        pool_size = mongo_config.pool_size
        self.client = MongoClient(host, port,maxPoolSize=pool_size)
        self.db = self.client.admin
        try:
            self.db.authenticate(user, pwd)
        except:
            logging.error(traceback.format_exc())

    # @classmethod
    # def getInstance(cls,config):
    #     if cls._instance is None:
    #         cls._instance = cls(config)
    #     return cls._instance

    # def getInstance(cls,config):
    #     if cls._instance is None:
    #         cls._instance = cls(config)
    #     return cls._instance

    def getMongoDbName(self, brandCode):
        """
        获取品牌对应数据库的dbname
        """
        # dbName = brandMongoDbNameMapping.get(brandCode, brandCode)
        return brandCode

    def get_db(self, db_name):
        """获取数据库连接"""
        db_name = self.getMongoDbName(db_name)
        return getattr(self.client,db_name)

    def get_coll_names(self):
        return self._CLIENT.getCollectionNames()

    def insert(self, db_name, coll_name, data, **kwargs):
        """插入数据"""

        db = self.get_db(db_name)
        db[coll_name].insert(data, **kwargs)

    def insert_many(self, db_name, coll_name, data_list):
        """批量"""
        db = self.get_db(db_name)
        db[coll_name].insert_many(data_list)

    def find(self, db_name, coll_name, *args, **kwargs):
        """查询数据"""

        db = self.get_db(db_name)
        return db[coll_name].find(*args, **kwargs)

    def find_one(self, db_name, coll_name, query, *args):
        """查询单条数据"""

        db = self.get_db(db_name)
        return db[coll_name].find_one(query, *args)

    def find_one_by_id(self, db_name, coll_name, doc_id, *args):
        """查询单条数据"""

        query = {'_id': doc_id}

        db = self.get_db(db_name)
        return db[coll_name].find_one(query, *args)

    def find_record_not_by_id(self, db_name, coll_name, query, *args):
        """不通过 _id 查询"""

        db = self.get_db(db_name)
        return db[coll_name].find_one(query, *args)

    def push(self, db_name, coll_name, query, data, **kwargs):
        """设置文档数据"""
        self.update(db_name, coll_name, query, {'$push': data}, **kwargs)


    def upsert(self, db_name, coll_name, query, data):
        self.update(db_name, coll_name, query, data,upsert=True)

    def find_and_modify(self, db_name, coll_name, query, update, **kwargs):
        """修改并查找"""

        db = self.get_db(db_name)
        return db[coll_name].find_and_modify(query, update, **kwargs)

    def set(self, db_name, coll_name, query, data, **kwargs):
        """设置文档数据"""

        res = self.update(db_name, coll_name, query, {'$set': data}, **kwargs)
        return res

    def set_many(self, db_name, coll_name, query, data, **kwargs):
        """设置文档数据"""

        res = self.update_many(db_name, coll_name, query, {'$set': data}, **kwargs)
        return res

    def unset(self, db_name, coll_name, query, data, **kwargs):
        """删除文档字段"""

        res = self.update(db_name, coll_name, query, {'$unset': data}, **kwargs)
        return res

    def set_one(self, db_name, coll_name, doc_id, data, **kwargs):
        """设置文档数据"""

        query = {'_id': doc_id}
        self.update(db_name, coll_name, query, {'$set': data}, **kwargs)

    def inc(self, db_name, coll_name, query, data, **kwargs):
        """文档对应字段数据数值增加"""

        self.update(db_name, coll_name, query, {'$inc': data}, **kwargs)

    def distinct(self, db_name, coll_name, key, query, **kwargs):
        """去重数据"""
        db = self.get_db(db_name)
        return db[coll_name].distinct(key, query, **kwargs)

    def inc_one(self, db_name, coll_name, doc_id, data, **kwargs):
        """文档对应字段数据数值增加"""

        query = {'_id': doc_id}
        self.update(db_name, coll_name, query, {'$inc': data}, **kwargs)

    def add_to_set(self, db_name, coll_name, query, data, **kwargs):
        """数组添加元素"""

        return self.update(db_name, coll_name, query, {'$addToSet': data},
                          **kwargs)

    def pull(self, db_name, coll_name, query, data, **kwargs):
        """删除数组元素"""

        return self.update(db_name, coll_name, query, {'$pull': data}, **kwargs)

    def update_or_insert(self, db_name, coll_name, query, data):
        """更新或者插入"""

        db = self.get_db(db_name)
        # return self.update(db_name, coll_name, query, data, upsert=True)
        return db[coll_name].update_one(query, {"$set": data}, upsert=True)

    def update(self, db_name, coll_name, query, update, **kwargs):
        """更新数据"""

        db = self.get_db(db_name)
        return db[coll_name].update(query, update, **kwargs)

    def update_many(self, db_name, coll_name, query, update, **kwargs):
        """更新数据"""

        db = self.get_db(db_name)
        return db[coll_name].update_many(query, update, **kwargs)

    def remove(self, db_name, coll_name, doc_id=None, multi=True, **kwargs):
        """删除数据"""
        query = {'_id': doc_id}
        db = self.get_db(db_name)
        db[coll_name].remove(query, multi, **kwargs)

    def delete_many(self,db_name,coll_name,query):
        '''
        批量删除
        :param db_name:
        :param coll_name:
        :param query:
        :return:
        '''
        db = self.get_db(db_name)
        print(query)
        if query and isinstance(query,dict):
            db[coll_name].delete_many(query)

    def getDb(self, db_name, coll_name):
        """获取集合实例"""
        db = self.get_db(db_name)
        return db[coll_name]


class AsynMongoApi(object):
    """MongoDB 数据库管理类"""
    # 配置文件解析对象


    def init_db(self,mongo_config):
        host = mongo_config.host
        port = mongo_config.port
        user = mongo_config.user
        pwd = mongo_config.pwd

        if user and pwd:
            self.motor_uri = f"mongodb://{user}:{pwd}@{host}:{port}/admin?authSource=admin"
        else:
            self.motor_uri = f"mongodb://{host}:{port}/admin"
        self.client = AsyncIOMotorClient(self.motor_uri)
        self.db = self.client.admin

    def getMongoDbName(self, brandCode):
        """
        获取品牌对应数据库的dbname
        """
        # dbName = brandMongoDbNameMapping.get(brandCode, brandCode)
        return brandCode

    def get_db(self, db_name):
        """获取数据库连接"""
        db_name = self.getMongoDbName(db_name)
        return getattr(self.client, db_name)

    async def find(self,db_name,collection,query,document):
        '''
        查询
        :param db_name:
        :param collection:
        :param query:
        :param document:
        :return:
        '''
        db = self.get_db(db_name)
        cursor = await db.find(collection,query,document)
        return await cursor.to_list()

    async def do_count(self,db_name,collection,query={}):
        '''
        计算行数
        :param db_name:
        :param collection:
        :param query:
        :return:
        '''
        db = self.get_db(db_name)
        return await getattr(db,collection).count_documents(query)

    async def find_one(self,db_name,coll,query,document):
        '''
        查询一条数据
        :param db_name:
        :param coll:
        :param query:
        :param document:
        :return:
        '''
        db = self.get_db(db_name)
        resutl = await db.find_one(coll, query, document)
        return resutl


